home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 August: Tool Chest / Dev.CD Aug 98 TC.toast / Sample Code / Overview / CPlusTESample / TESample.cp < prev    next >
Encoding:
Text File  |  1994-11-18  |  11.5 KB  |  486 lines  |  [TEXT/MPS ]

  1. /*------------------------------------------------------------------------------------------
  2.  
  3.     Program:    CPlusTESample 2.0
  4.     File:        TESample.cp
  5.     Uses:       TEDocument.h
  6.                 TESample.h
  7.  
  8.     by Andrew Shebanow
  9.     of Apple Macintosh Developer Technical Support
  10.  
  11.     Copyright © 1989-1990 Apple Computer, Inc.
  12.     All rights reserved.
  13.  
  14. ------------------------------------------------------------------------------------------*/
  15.  
  16. #ifndef __TYPES__
  17. #include <Types.h>
  18. #endif
  19. #ifndef __QUICKDRAW__
  20. #include <QuickDraw.h>
  21. #endif
  22. #ifndef __FONTS__
  23. #include <Fonts.h>
  24. #endif
  25. #ifndef __EVENTS__
  26. #include <Events.h>
  27. #endif
  28. #ifndef __CONTROLS__
  29. #include <Controls.h>
  30. #endif
  31. #ifndef __WINDOWS__
  32. #include <Windows.h>
  33. #endif
  34. #ifndef __MENUS__
  35. #include <Menus.h>
  36. #endif
  37. #ifndef __TEXTEDIT__
  38. #include <TextEdit.h>
  39. #endif
  40. #ifndef __DIALOGS__
  41. #include <Dialogs.h>
  42. #endif
  43. #ifndef __MENUS__
  44. #include <Menus.h>
  45. #endif
  46. #ifndef __DEVICES__
  47. #include <Devices.h>
  48. #endif
  49. #ifndef __SCRAP__
  50. #include <Scrap.h>
  51. #endif
  52. #ifndef __TOOLUTILS__
  53. #include <ToolUtils.h>
  54. #endif
  55. #ifndef __MEMORY__
  56. #include <Memory.h>
  57. #endif
  58. #ifndef __SEGLOAD__
  59. #include <SegLoad.h>
  60. #endif
  61. #ifndef __FILES__
  62. #include <Files.h>
  63. #endif
  64. #ifndef __OSUTILS__
  65. #include <OSUtils.h>
  66. #endif
  67. #ifndef __TRAPS__
  68. #include <Traps.h>
  69. #endif
  70. #ifndef __PACKAGES__
  71. #include <Packages.h>
  72. #endif
  73. #ifndef __ERRORS__
  74. #include <Errors.h>
  75. #endif
  76.  
  77. // our class definitions
  78. #include "TEDocument.h"
  79. #include "TESample.h"
  80.  
  81. // ExtremeNeg and ExtremePos are used to set up wide open rectangles and regions.
  82. const short kExtremeNeg = -32768;
  83. const short kExtremePos = 32767 - 1; // required to address an old region bug
  84.  
  85. // kMaxOpenDocuments is used to determine whether a new document can be opened
  86. // or created. We keep track of the number of open documents, and disable the
  87. // menu items that create a new document when the maximum is reached. If the
  88. // number of documents falls below the maximum, the items are enabled again.
  89. const short    kMaxOpenDocuments = 4;
  90.  
  91. const OSType kCreatorType = 'MOOT';
  92.  
  93. // Define max and min macros for efficiency.
  94. #define max(a,b)        ((a) > (b) ? (a) : (b))
  95. #define min(a,b)        ((a) < (b) ? (a) : (b))
  96.  
  97. // Our application object, initialized in main(). We make it
  98. // global so our functions which don't belong to any class
  99. // can find the active document.
  100. TESample* gTheApplication;
  101.  
  102. // main is the entrypoint to the program
  103. int main()
  104. {
  105.     // Create our application object. This MUST be the FIRST thing
  106.     // done in main(), since it initializes the Toolbox for us.
  107.     gTheApplication = new TESample;
  108.     if (gTheApplication == nil)        // if we couldn't allocate object (impossible!?)
  109.       ExitToShell();                // go back to Finder
  110.  
  111.     gTheApplication->ProcessArgs();
  112.  
  113.     // Start our main event loop running. This won't return until user quits
  114.     gTheApplication->EventLoop();
  115.  
  116.     // We always return a value, like good little ANSI worshippers,
  117.     // so that the compiler won't complain
  118.     return 0;
  119. }
  120.  
  121. // the constructor for our class, called automatically when we create
  122. // an instance of this class. In this particular case, we only want
  123. // one instance since the constructor does all the menu setups and
  124. // creates our (untitled) document.
  125. // Note that we call our base TApplication constructor, passing it
  126. // our creator signature constant.
  127. TESample::TESample() : TApplication(kCreatorType)
  128. {
  129.     Handle    menuBar;
  130.  
  131.     // read menus into menu bar
  132.     menuBar = GetNewMBar(rMenuBar);
  133.     // install menus
  134.     SetMenuBar(menuBar);
  135.     DisposeHandle(menuBar);
  136.     // add DA names to Apple menu
  137.     AppendResMenu(GetMenuHandle(mApple), 'DRVR');
  138.     DrawMenuBar();
  139.  
  140.     // create empty mouse region
  141.     fMouseRgn = NewRgn();
  142.     // make sure we have a valid cursor region
  143.     AdjustCursor();
  144. }
  145.  
  146. // Tell TApplication class how much heap we need
  147. long TESample::HeapNeeded()
  148. {
  149.     return (kMinSize * 1024);
  150. }
  151.  
  152. // Calculate a sleep value for WaitNextEvent. This takes into account the things
  153. // that DoIdle does with idle time.
  154.  
  155. unsigned long TESample::SleepVal()
  156. {
  157.     unsigned long sleep;
  158.  
  159.     sleep = kMaxSleepTime;                // default value for sleep
  160.     // if we aren't in background, let document tell us how long to sleep
  161.     if ((!fInBackground) && (fCurDoc != nil))
  162.       sleep = min(sleep,fCurDoc->CalcIdle());
  163.     return sleep;
  164. }
  165.  
  166. // This is called whenever we get a null event et al.
  167. // It takes care of necessary periodic actions. For this program,
  168. // it calls TEIdle.
  169.  
  170. void TESample::DoIdle()
  171. {
  172.     TEDocument* fTECurDoc = (TEDocument*) fCurDoc;
  173.  
  174.     if (fTECurDoc != nil)
  175.       fTECurDoc->DoIdle();
  176. } // DoIdle
  177.  
  178. // Change the cursor's shape, depending on its position. This also calculates a
  179. // region that includes the cursor for WaitNextEvent.
  180.  
  181. void TESample::AdjustCursor()
  182. {
  183.     TEDocument* fTECurDoc = (TEDocument*) fCurDoc;
  184.  
  185.     // notice that we don't change cursor if front window isn't ours
  186.     if ( (!fInBackground) && (fTECurDoc != nil) )
  187.       {
  188.         RgnHandle    arrowRgn;
  189.         RgnHandle    iBeamRgn;
  190.         Point        mouse;
  191.  
  192.         // get mouse location and convert to global coordinates
  193.         GetMouse(&mouse);
  194.         LocalToGlobal(&mouse);
  195.  
  196.         // calculate regions for different cursor shapes
  197.         arrowRgn = NewRgn();
  198.         iBeamRgn = NewRgn();
  199.         // start arrowRgn wide open
  200.         SetRectRgn(arrowRgn, kExtremeNeg, kExtremeNeg, kExtremePos, kExtremePos);
  201.         // calculate iBeamRgn
  202.         fTECurDoc->GetVisTERgn(iBeamRgn);
  203.         // subtract iBeamRgn from arrowRgn
  204.         DiffRgn(arrowRgn, iBeamRgn, arrowRgn);
  205.  
  206.         // change the cursor and the region parameter
  207.         if (PtInRgn(mouse, iBeamRgn))
  208.           {
  209.             SetCursor(*GetCursor(iBeamCursor));
  210.             CopyRgn(iBeamRgn, fMouseRgn);
  211.           }
  212.         else
  213.           {
  214.             SetCursor(&qd.arrow);
  215.             CopyRgn(arrowRgn, fMouseRgn);
  216.           }
  217.         // get rid of regions we don't need anymore
  218.         DisposeRgn(arrowRgn);
  219.         DisposeRgn(iBeamRgn);
  220.       }
  221. } // AdjustCursor
  222.  
  223. // Enable and disable menus based on the current state. The
  224. // user can only select enabled menu items. We set up all the
  225. // menu items before calling MenuSelect or MenuKey, since
  226. // these are the only times that a menu item can be selected.
  227. // Note that MenuSelect is also the only time the user will
  228. // see menu items. This approach to deciding what enable/
  229. // disable state a menu item has the advantage of
  230. // concentrating all the decision-making in one routine, as
  231. // opposed to being spread throughout the application. Other
  232. // application designs may take a different approach that may
  233. // or may not be as valid.
  234.  
  235. void TESample::AdjustMenus()
  236. {
  237.     WindowPtr    frontmost;
  238.     MenuHandle    fileMenu, editMenu;
  239.     long        offset;
  240.     Boolean        undo;
  241.     Boolean        cutCopyClear;
  242.     Boolean        paste;
  243.     Boolean        save, saveAs;
  244.     Boolean        selectAll;
  245.     TEDocument* fTECurDoc = (TEDocument*) fCurDoc;
  246.  
  247.     frontmost = FrontWindow();
  248.  
  249.     fileMenu = GetMenuHandle(mFile);
  250.     if (fDocList->NumDocs() < kMaxOpenDocuments)
  251.       {
  252.         // New & Open are enabled when we can open more documents
  253.         EnableItem(fileMenu, iNew);
  254.         EnableItem(fileMenu, iOpen);
  255.       }
  256.     else
  257.       {
  258.         DisableItem(fileMenu, iNew);
  259.         DisableItem(fileMenu, iOpen);
  260.       }
  261.     if (frontmost != (WindowPtr) nil)    // Close is enabled when there is a window to close
  262.       EnableItem(fileMenu, iClose);
  263.     else DisableItem(fileMenu, iClose);
  264.  
  265.     editMenu = GetMenuHandle(mEdit);
  266.     undo = false;
  267.     cutCopyClear = false;
  268.     paste = false;
  269.     save = saveAs = false;
  270.     selectAll = false;
  271.     if (frontmost != nil)
  272.       {
  273.         selectAll = true;
  274.         if (fCurDoc == nil)
  275.           {
  276.             undo = true;                // all editing is enabled for DA windows
  277.             cutCopyClear = true;
  278.             paste = true;
  279.           }
  280.         else
  281.           {
  282.             // Cut, Copy, and Clear is enabled for app. windows with selections
  283.             if ( fTECurDoc->HaveSelection() )
  284.               cutCopyClear = true;
  285.             // If we have any TEXT in the scrap, enable paste
  286.             if ( GetScrap(nil, 'TEXT', &offset) )
  287.                 paste = true;
  288.             // enable save if we are dirty
  289.             save = fCurDoc->CanSave();
  290.             saveAs = fCurDoc->CanSaveAs();
  291.           }
  292.       }
  293.     if (save)
  294.       EnableItem(fileMenu, iSave);
  295.     else DisableItem(fileMenu, iSave);
  296.     if (saveAs)
  297.       EnableItem(fileMenu, iSaveAs);
  298.     else DisableItem(fileMenu, iSaveAs);
  299.  
  300.     if (undo)
  301.       EnableItem(editMenu, iUndo);
  302.     else DisableItem(editMenu, iUndo);
  303.     if ( cutCopyClear )
  304.       {
  305.         EnableItem(editMenu, iCut);
  306.         EnableItem(editMenu, iCopy);
  307.         EnableItem(editMenu, iClear);
  308.       }
  309.     else
  310.       {
  311.         DisableItem(editMenu, iCut);
  312.         DisableItem(editMenu, iCopy);
  313.         DisableItem(editMenu, iClear);
  314.       }
  315.     if (paste)
  316.       EnableItem(editMenu, iPaste);
  317.     else DisableItem(editMenu, iPaste);
  318.     if (selectAll)
  319.       EnableItem(editMenu, iSelectAll);
  320.     else DisableItem(editMenu, iSelectAll);
  321. } // AdjustMenus
  322.  
  323.  
  324. // This is called when an item is chosen from the menu bar (after calling
  325. // MenuSelect or MenuKey). It does the right thing for each command.
  326.  
  327. void TESample::DoMenuCommand(short menuID, short menuItem)
  328. {
  329.     short        itemHit;
  330.     Str255        daName;
  331.     short        daRefNum;
  332.     WindowPtr    window;
  333.     TEDocument* fTECurDoc = (TEDocument*) fCurDoc;
  334.  
  335.     window = FrontWindow();
  336.     switch ( menuID )
  337.       {
  338.         case mApple:
  339.             switch ( menuItem )
  340.               {
  341.                 case iAbout:        // bring up alert for About
  342.                     itemHit = Alert(rAboutAlert, nil);
  343.                     break;
  344.                 default:            // all non-About items in this menu are DAs et al
  345.                     GetMenuItemText(GetMenuHandle(mApple), menuItem, daName);
  346.                     daRefNum = OpenDeskAcc(daName);
  347.                     break;
  348.               }
  349.             break;
  350.         case mFile:
  351.             switch ( menuItem )
  352.               {
  353.                 case iNew:
  354.                     DoNew();
  355.                     break;
  356.                 case iOpen:
  357.                     DoOpen();
  358.                     break;
  359.                 case iClose:
  360.                     if (fTECurDoc != nil)
  361.                       {
  362.                         // only close the document if the user doesn't cancel
  363.                         if (fTECurDoc->DoClose(true, yesResult, false) != cancelResult)
  364.                           {
  365.                             fDocList->RemoveDoc(fTECurDoc);
  366.                             delete fTECurDoc;
  367.                           }
  368.                       }
  369.                     else CloseDeskAcc(((WindowPeek) fWhichWindow)->windowKind);
  370.                     // make sure our current document/window references are valid
  371.                     fWhichWindow = FrontWindow();
  372.                     if (fWhichWindow != nil)
  373.                       {
  374.                         fCurDoc = fDocList->FindDoc(fWhichWindow);
  375.                         SetPort(fWhichWindow);
  376.                       }
  377.                     else fCurDoc = nil;
  378.                     break;
  379.                 case iSave:
  380.                     if (fTECurDoc != nil)
  381.                       fTECurDoc->DoSave();
  382.                     break;
  383.                 case iSaveAs:
  384.                     if (fTECurDoc != nil)
  385.                       fTECurDoc->DoSaveAs();
  386.                     break;
  387.                 case iQuit:
  388.                     DoQuit(true, yesResult);
  389.                     break;
  390.               }
  391.             break;
  392.         case mEdit:                    // call SystemEdit for DA editing & MultiFinder
  393.             if (!SystemEdit(menuItem-1))
  394.               {
  395.                 switch (menuItem)
  396.                   {
  397.                     case iCut:
  398.                         fTECurDoc->DoCut();
  399.                         break;
  400.                     case iCopy:
  401.                         fTECurDoc->DoCopy();
  402.                         break;
  403.                     case iPaste:
  404.                         fTECurDoc->DoPaste();
  405.                         break;
  406.                     case iClear:
  407.                         fTECurDoc->DoClear();
  408.                         break;
  409.                     case iSelectAll:
  410.                         fTECurDoc->DoSelectAll();
  411.                         break;
  412.                    }
  413.               }
  414.             break;
  415.       }
  416.     HiliteMenu(0);                    // unhighlight what MenuSelect (or MenuKey) hilited
  417. } // DoMenuCommand
  418.  
  419. // Create a new document and window.
  420.  
  421. void TESample::DoNew()
  422. {
  423.     TEDocument* tDoc;
  424.  
  425.     tDoc = new TEDocument(rDocWindow);
  426.     FailNIL(tDoc);
  427.  
  428.     TRY
  429.       {
  430.         tDoc->OpenNewDoc();
  431.         fDocList->AddDoc(tDoc);
  432.       }
  433.     RECOVER
  434.       {
  435.         delete tDoc;
  436.       }
  437.     ENDTRY
  438. } // DoNew
  439.  
  440. void TESample::OpenADoc(short vRefNum, long dirID, StringPtr fName, OSType fType)
  441. {
  442.     if (fType != kTEFileType)
  443.       Failure(eBadFileType,kTEDocErrStrings);
  444.  
  445.     TEDocument* tDoc = new TEDocument(rDocWindow);
  446.     FailNIL(tDoc);
  447.  
  448.     TRY
  449.       {
  450.         CanonicalFileSpec fileSpec;
  451.  
  452.         fileSpec.vRefNum = vRefNum;
  453.         fileSpec.dirID = dirID;
  454.         CopyPString(fileSpec.fileName, fName);
  455.  
  456.         tDoc->OpenOldDoc(fileSpec,false);
  457.         fDocList->AddDoc(tDoc);
  458.       }
  459.     RECOVER
  460.       {
  461.         delete tDoc;
  462.       }
  463.     ENDTRY
  464. }
  465.  
  466. void TESample::DoOpen()
  467. {
  468.     Point where;
  469.     Str255 prompt;
  470.     SFTypeList typeList;
  471.     SFReply reply;
  472.     short vRefNum;
  473.     long dirID;
  474.  
  475.     SetPt(&where,100,100);
  476.     prompt[0] = '\0';
  477.     typeList[0] = kTEFileType;
  478.     SFGetFile(where,prompt,(FileFilterProcPtr) nil,
  479.               1,typeList,(DlgHookProcPtr) nil,&reply);
  480.     if (reply.good == false)
  481.       return;
  482.  
  483.     WDToDirID(reply.vRefNum,vRefNum,dirID);
  484.     OpenADoc(vRefNum,dirID,reply.fName, kTEFileType);
  485. }
  486.